# app/core/jwt.py
import uuid
from datetime import datetime, timedelta, timezone
from typing import Any, Dict

from jose import JWTError, jwt


class JWTUtils:
    """
    JWT 令牌服务类

    提供创建和解码 JWT 令牌的功能，支持访问令牌和刷新令牌。
    所有敏感参数（如密钥、算法、有效期）通过初始化传入，便于测试和多环境配置。
    """

    def __init__(
        self,
        secret_key: str,
        algorithm: str = "HS256",
        access_token_lifetime: int = 30,  # minutes
        refresh_token_lifetime: int = 7,  # days
    ):
        if not secret_key:
            raise ValueError("secret_key 不能为空")
        self.secret_key = secret_key
        self.algorithm = algorithm
        self.access_token_lifetime = access_token_lifetime
        self.refresh_token_lifetime = refresh_token_lifetime

    def _create_token(self, data: Dict[str, Any], expires_delta: timedelta) -> str:
        """创建 JWT 令牌"""
        to_encode = data.copy()
        now = datetime.now(timezone.utc)
        expire = now + expires_delta
        jti = str(uuid.uuid4())

        to_encode.update(
            {
                "exp": expire,
                "iat": now,
                "jti": jti,
            }
        )

        return jwt.encode(to_encode, self.secret_key, algorithm=self.algorithm)

    def create_access_token(self, data: Dict[str, Any]) -> str:
        """创建访问令牌"""
        payload = {**data, "type": "access"}
        return self._create_token(payload, timedelta(minutes=self.access_token_lifetime))

    def create_refresh_token(self, data: Dict[str, Any]) -> str:
        """创建刷新令牌"""
        payload = {**data, "type": "refresh"}
        return self._create_token(payload, timedelta(days=self.refresh_token_lifetime))

    def create_tokens(self, data: Dict[str, Any]) -> Dict[str, str]:
        """同时创建访问令牌和刷新令牌"""
        access_token = self.create_access_token(data)
        refresh_token = self.create_refresh_token(data)

        return {"access_token": access_token, "refresh_token": refresh_token}

    def decode_token(self, token: str) -> Dict[str, Any]:
        """通用解码方法（不验证类型）"""
        return jwt.decode(token, self.secret_key, algorithms=[self.algorithm])

    def decode_access_token(self, token: str) -> Dict[str, Any]:
        """解码并验证访问令牌"""
        payload = self.decode_token(token)
        if payload.get("type") != "access":
            raise JWTError("Invalid token type: expected 'access'")
        return payload

    def decode_refresh_token(self, token: str) -> Dict[str, Any]:
        """解码并验证刷新令牌"""
        payload = self.decode_token(token)
        if payload.get("type") != "refresh":
            raise JWTError("Invalid token type: expected 'refresh'")
        return payload
